﻿#if (!PCL) && ((!UNITY_5) || UNITY_STANDALONE)

using MoonSharp.Interpreter;
using MoonSharp.VsCodeDebugger.SDK;
using System.Collections.Generic;

namespace MoonSharp.VsCodeDebugger.DebuggerLogic
{
    internal class EmptyDebugSession : DebugSession
    {
        MoonSharpVsCodeDebugServer m_Server;

        internal EmptyDebugSession(MoonSharpVsCodeDebugServer server)
            : base(true, false)
        {
            m_Server = server;
        }

        public override void Initialize(Response response, Table args)
        {
#if DOTNET_CORE
			SendText("Connected to MoonSharp {0} [{1}]",
					 Script.VERSION,
					 Script.GlobalOptions.Platform.GetPlatformName());
#else
            SendText("Empty Debug Session - Connected to MoonSharp {0} [{1}] on process {2} (PID {3})",
                Script.VERSION,
                Script.GlobalOptions.Platform.GetPlatformName(),
                System.Diagnostics.Process.GetCurrentProcess().ProcessName,
                System.Diagnostics.Process.GetCurrentProcess().Id);
#endif

            SendText(
                "No script is set as default for debugging; use the debug console to select the script to debug.\n");

            SendText("Debugger is ready to be hacked");


            SendList();

            SendResponse(response, new Capabilities()
            {
                // This debug adapter does not need the configurationDoneRequest.
                supportsConfigurationDoneRequest = false,

                // This debug adapter does not support function breakpoints.
                supportsFunctionBreakpoints = false,

                // This debug adapter doesn't support conditional breakpoints.
                supportsConditionalBreakpoints = false,

                // This debug adapter does not support a side effect free evaluate request for data hovers.
                supportsEvaluateForHovers = false,

                // This debug adapter does not support exception breakpoint filters
                exceptionBreakpointFilters = new object[0]
            });

            // Debugger is ready to accept breakpoints immediately
            SendEvent(new InitializedEvent());
        }

        private void SendList()
        {
            int currId = m_Server.CurrentId ?? -1000;

            SendText("==========================================================");

            foreach (var pair in m_Server.GetAttachedDebuggersByIdAndName())
            {
                string isdef = (pair.Key == currId) ? " (default)" : "";
                SendText("{0} : {1}{2}", pair.Key.ToString().PadLeft(9), pair.Value, isdef);
            }

            SendText("");
            SendText("Type the number of the script to debug, or '!' to refresh");
        }

        public override void Attach(Response response, Table arguments)
        {
            SendResponse(response);
        }

        public override void Continue(Response response, Table arguments)
        {
            SendList();
            SendResponse(response);
        }

        public override void Disconnect(Response response, Table arguments)
        {
            SendResponse(response);
        }

        private static string getString(Table args, string property, string dflt = null)
        {
            var s = (string) args[property];
            if (s == null)
            {
                return dflt;
            }

            s = s.Trim();
            if (s.Length == 0)
            {
                return dflt;
            }

            return s;
        }

        public override void Evaluate(Response response, Table args)
        {
            var expression = getString(args, "expression");
            var context = getString(args, "context") ?? "hover";

            if (context == "repl")
                ExecuteRepl(expression);

            SendResponse(response);
        }

        private void ExecuteRepl(string cmd)
        {
            int id = 0;
            if (int.TryParse(cmd, out id))
            {
                m_Server.CurrentId = id;

                SendText("Re-attach the debugger to debug the selected script.");

                Unbind();
            }
            else
            {
                SendList();
            }
        }


        public override void Launch(Response response, Table arguments)
        {
            SendResponse(response);
        }

        public override void Next(Response response, Table arguments)
        {
            SendList();
            SendResponse(response);
        }

        public override void Pause(Response response, Table arguments)
        {
            SendList();
            SendResponse(response);
        }

        public override void Scopes(Response response, Table arguments)
        {
            SendResponse(response);
        }

        public override void SetBreakpoints(Response response, Table args)
        {
            SendResponse(response);
        }

        public override void StackTrace(Response response, Table args)
        {
            SendResponse(response);
        }


        public override void StepIn(Response response, Table arguments)
        {
            SendList();
            SendResponse(response);
        }

        public override void StepOut(Response response, Table arguments)
        {
            SendList();
            SendResponse(response);
        }

        public override void Threads(Response response, Table arguments)
        {
            var threads = new List<Thread>() {new Thread(0, "Main Thread")};
            SendResponse(response, new ThreadsResponseBody(threads));
        }


        public override void Variables(Response response, Table arguments)
        {
            SendResponse(response);
        }


        private void SendText(string msg, params object[] args)
        {
            msg = string.Format(msg, args);
            SendEvent(new OutputEvent("console", msg + "\n"));
        }


        public void Unbind()
        {
            SendText("Bye.");
            SendEvent(new TerminatedEvent());
        }
    }
}
#endif